{
 "cells": [
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-18T15:36:43.929878Z",
     "start_time": "2025-09-18T15:36:43.906849Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def resize(image, width=None, height=None, inter=cv2.INTER_AREA):\n",
    "\tdim = None\n",
    "\t(h, w) = image.shape[:2]\n",
    "\tif width is None and height is None:\n",
    "\t\treturn image\n",
    "\tif width is None:\n",
    "\t\tr = height / float(h)\n",
    "\t\tdim = (int(w * r), height)\n",
    "\telse:\n",
    "\t\tr = width / float(w)\n",
    "\t\tdim = (width, int(h * r))\n",
    "\tresized = cv2.resize(image, dim, interpolation=inter)\n",
    "\treturn resized\n",
    "\n",
    "def order_points(pts):\n",
    "\t# 一共4个坐标点\n",
    "\trect = np.zeros((4, 2), dtype = \"float32\")\n",
    "\n",
    "\t# 按顺序找到对应坐标0123分别是 左上，右上，右下，左下\n",
    "\t# 计算左上，右下\n",
    "\ts = pts.sum(axis = 1)\n",
    "\trect[0] = pts[np.argmin(s)]\n",
    "\trect[2] = pts[np.argmax(s)]\n",
    "\n",
    "\t# 计算右上和左下\n",
    "\tdiff = np.diff(pts, axis = 1)\n",
    "\trect[1] = pts[np.argmin(diff)]\n",
    "\trect[3] = pts[np.argmax(diff)]\n",
    "\n",
    "\treturn rect\n",
    "\n",
    "def four_point_transform(image, pts):\n",
    "\t# 获取输入坐标点\n",
    "\trect = order_points(pts)\n",
    "\t(tl, tr, br, bl) = rect\n",
    "\n",
    "\t# 计算输入的w和h值\n",
    "\twidthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))\n",
    "\twidthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))\n",
    "\tmaxWidth = max(int(widthA), int(widthB))\n",
    "\n",
    "\theightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))\n",
    "\theightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))\n",
    "\tmaxHeight = max(int(heightA), int(heightB))\n",
    "\n",
    "\t# 变换后对应坐标位置\n",
    "\tdst = np.array([\n",
    "\t\t[0, 0],\n",
    "\t\t[maxWidth - 1, 0],\n",
    "\t\t[maxWidth - 1, maxHeight - 1],\n",
    "\t\t[0, maxHeight - 1]], dtype = \"float32\")\n",
    "\n",
    "\t# 计算变换矩阵\n",
    "\tM = cv2.getPerspectiveTransform(rect, dst)\n",
    "\twarped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))\n",
    "\n",
    "\t# 返回变换后结果\n",
    "\treturn warped\n"
   ],
   "id": "f5411d4ba52b42c2",
   "outputs": [],
   "execution_count": 9
  },
  {
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-09-18T15:51:07.420146Z",
     "start_time": "2025-09-18T15:44:28.193349Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import numpy as np\n",
    "import argparse\n",
    "import cv2\n",
    "\n",
    "def cv_show(img, title='image'):\n",
    "    cv2.imshow(title, img)\n",
    "    cv2.waitKey(0)\n",
    "    cv2.destroyAllWindows()\n",
    "\n",
    "image = cv2.imread(r'data/receipt.jpg')\n",
    "ratio = image.shape[0] / 500.0 # 记录缩放比例\n",
    "orig = image.copy()\n",
    "image = resize(orig, height = 500) # 缩放高度到500px\n",
    "# cv_show(image)\n",
    "\n",
    "# 预处理\n",
    "gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
    "gray = cv2.GaussianBlur(gray, (5, 5), 0)\n",
    "edged = cv2.Canny(gray, 75, 200)\n",
    "cv_show(edged)\n",
    "\n",
    "cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]\n",
    "cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]\n",
    "\n",
    "for c in cnts:\n",
    "    peri = cv2.arcLength(c, True)\n",
    "    approx = cv2.approxPolyDP(c, 0.02 * peri, True)\n",
    "\n",
    "    if len(approx) == 4:\n",
    "        screenCnt = approx\n",
    "        break\n",
    "\n",
    "\n",
    "print(\"STEP 2: Find contours of paper\")\n",
    "cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)\n",
    "cv_show(image)\n",
    "\n",
    "warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)\n",
    "\n",
    "warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)\n",
    "ref = cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1]\n",
    "cv2.imshow(\"Original\", resize(orig, width = 600))\n",
    "cv2.imshow(\"Scanned\", resize(warped, width = 600))\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ],
   "id": "initial_id",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "STEP 2: Find contours of paper\n"
     ]
    }
   ],
   "execution_count": 12
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "87efd13b7fa820e6"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
